﻿using System;
using System.Collections.Concurrent;
using NLua;
using Development.Tools;
using System.IO;

namespace Development.Script
{
    public class LuaRunTime : Singleton<LuaRunTime>, IScriptRunTime, IDisposable
    {
        private readonly string _codeName = "Lua";
        private ConcurrentDictionary<string, Lua> _scopes = new ConcurrentDictionary<string, Lua>();
        private FileSystemWatcher _fileWatcher = null;

        public void LoadScript()
        {
            var files = ScriptUtil.GetScriptFiles(_codeName);
            foreach (var f in files)
            {
                try
                {
                    var l = new Lua();
                    l.DoFile(f);
                    string scopeName = Path.GetFileNameWithoutExtension(f);
                    _scopes.TryAdd(scopeName, l);

                }
                catch (Exception e)
                {
                    Log.WriteLog(ELogLevel.LOG_ERROR, "lua file = " + f + ";" + e.Message);
                    return;
                }
            }
            AddFileWatcher(ScriptUtil.GetScriptPath(_codeName), "*.lua");
        }

        private void AddFileWatcher(string path, string filter)
        {
            if (_fileWatcher == null)
            {
                _fileWatcher = new FileSystemWatcher(path, filter);
                _fileWatcher.Changed += watcher_Changed;
                _fileWatcher.EnableRaisingEvents = true;
            }
        }

        void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            string scopeName = Path.GetFileNameWithoutExtension(e.FullPath);
            try
            {
                var l = new Lua();
                l.DoFile(e.FullPath);
                if (_scopes.ContainsKey(scopeName))
                {
                    _scopes[scopeName].Close();
                    _scopes[scopeName] = l;
                }
                else
                {
                    _scopes.TryAdd(scopeName, l);
                }
                Log.WriteLog(ELogLevel.LOG_INFO, "reload lua name=" + scopeName);

            }
            catch (Exception ex)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, ex.Message);
            }
        }

        public dynamic GetScope(string className)
        {
            if (_scopes.ContainsKey(className))
            {
                return _scopes[className];
            }
            return null;
        }

        public object Invoke(string scope, string functionName, params object[] args)
        {
            Lua sc = GetScope(scope);
            LuaFunction fun = sc.GetFunction(functionName);
            if (fun != null)
            {
                return fun.Call(args);
            }
            return null;
        }

        public void Dispose()
        {
            if (_fileWatcher != null)
            {
                _fileWatcher.Dispose();
                foreach(var l in _scopes)
                {
                    l.Value.Close();
                }
                _scopes.Clear();
            }
        }
    }
}
